系列:從現場踩坑到 AI 工具 — IT Diagnostic Agent 開發實錄
先講清楚:Claude 沒有漲價,我也沒有遇到任何 API 政策問題。
這篇文章要講的,是一個還沒發生但我從第一版就在防的風險。
而我認為這比事後補救的故事更值得寫——因為架構決策的價值,恰恰在於它讓某些故事永遠不會發生。
我做 IT 基礎建設二十年,這行有一條很基本的紀律:
不要讓任何單一供應商掐住你的咽喉。
這不是不信任那些廠商。Cisco 沒有比較容易倒,中華電信不會突然斷線。
但**「他不會出問題」和「他出問題時我還活著」是兩件不同的事**。前者是預測,後者是設計。
當我開始接 LLM API 的時候,這個職業病自動就啟動了。
我把風險列出來的時候發現一件事:我擔心的沒有一項是「Claude 不夠好」。
API 定價是廠商單方面決定的。今天的 token 價格不保證是明年的價格。
而我的工具沒有後端、不收費、使用者自己付 API 錢——這代表定價變動的痛感會直接打在使用者身上,我連幫他們吸收成本的機制都沒有。
這一項不是假設,而且時間點近得有點剛好。
2026 年 6 月 9 日,Anthropic 發布了 Claude Fable 5 和 Mythos 5。
6 月 12 日,這兩個模型的存取權限被暫停,以配合美國商務部的出口管制。
6 月 30 日管制解除,7 月 1 日恢復服務。
也就是說,那兩個模型有將近三週的時間是不能用的。
而我這個工具是 6 月 10 日上 GitHub 的。 剛好卡在 Fable 5 發布之後、暫停之前那兩天。
但我完全沒受影響。 因為我開發用的是 Sonnet 4.6,工具的預設模型也是 Sonnet 系列。整件事對我來說,就只是一則新聞。
我想特別把這件事寫清楚,因為它比「我遇到問題然後 Adapter Pattern 救了我」更有說服力。
如果我當初剛好選了 Fable 5 來開發、或是把它設成工具的預設模型——純粹是模型選擇上的一個隨手決定——那三週我的工具就是壞的。
我不會有任何預警。使用者也不會知道發生什麼事,他們只會看到 API 回錯誤。
這就是供應商依賴風險的真正形狀:它不是「某家廠商比較不可靠」,而是「你會不會被打到,取決於你在一個無關的決策點上剛好選了哪一邊」。
而任何依賴運氣的架構,都只是還沒被抽到而已。
Adapter Pattern 做的事情,就是把「有沒有被打到」從運氣的範疇,移到設計的範疇——不是保證不被打到,是保證被打到的時候,切換成本是一個下拉選單,而不是三週的停擺。
順帶一提,Anthropic 在暫停和恢復這兩件事上都發了公開說明。他們的處理在我看來是合規範圍內能做到最透明的了。
這正是我要強調的:風險不需要有人做錯事才會發生。 一個所有參與者都行為正確的世界裡,你的工具照樣可能壞掉三週。
這個是最現實的。
我後來實際接觸企業需求時發現,有些客戶的第一個問題不是「準不準」,是「資料會不會出公司」。
只要工具只能接雲端 API,這個問題就沒有答案。(Day 19 會專門講這件事。)
Adapter Pattern(配接器模式)的概念很簡單:
定義一個統一的介面,讓不同的外部服務都被包裝成同一個形狀。
上層程式碼只認識那個介面,不認識任何一家供應商。
實際的程式碼是這樣:
async function callLLM(messages, systemPrompt){
switch(currentProvider){
case 'claude': return await callClaude(messages, systemPrompt);
case 'gemini': return await callGemini(messages, systemPrompt);
case 'openai': return await callOpenAI(messages, systemPrompt);
case 'ollama': return await callOllama(messages, systemPrompt);
default: throw new Error('Unknown provider: ' + currentProvider);
}
}
這段程式碼十行,但它是整個 AI 功能的樞紐。
Adapter Pattern 的核心不是那個 switch,是契約。
在這個專案裡,契約是:
(messages, systemPrompt) => Promise<string>
輸入: 對話歷史陣列 + 系統提示字串
輸出: 一個字串
每一個 callXXX 函式都必須符合這個形狀。至於它內部怎麼把 messages 轉成該供應商要的格式、怎麼從一坨巢狀 JSON 裡挖出回覆文字——那是各自 adapter 的責任,上層完全不需要知道。
這代表整個工具裡只有四個函式知道供應商的存在。其他所有程式碼都只呼叫 callLLM。
新增一家供應商的成本,是寫一個函式,加一行 case。
不需要動決策樹、不需要動 UI、不需要動 systemPrompt、不需要動聊天記錄管理。
這件事的價值在後來得到驗證:當我要加 Ollama 支援的時候,實際的工作量遠比我預期的小。因為架構已經在那裡等著了。(Day 18 會講這個。)
反過來想,如果我第一版把 fetch('https://api.anthropic.com/...') 直接寫在送出按鈕的事件處理裡,後來要加三家供應商,我得回頭重構所有跟 AI 有關的程式碼。
那個重構不會很難,但它會很煩,而煩到一定程度的事情就不會被做。
可控 vs 不可控
| 不可控 | 可控 |
|---|---|
| API 定價 | 換供應商的成本 |
| 廠商政策與法規 | 是否有替代路徑 |
| 服務可用性 | 切換所需的時間 |
我控制不了左邊任何一項。Adapter Pattern 做的事情是:把右邊那一欄從「幾天的重構」壓到「一個函式」。
風險沒有消失,但應對風險的成本被壓到接近零。
核心 vs 外部
核心是「工具要能用」。哪一家供應商提供智能,是外部條件。
一個把外部條件寫進核心邏輯的架構,會讓外部的每一次波動都變成核心的問題。
靜態 vs 動態
供應商生態是動態的。2026 年的最佳選擇不會是 2028 年的最佳選擇。
一個假設「供應商固定」的架構,是用靜態設計去對應動態現實。
寫到這裡可能會有人覺得:這是不是在避險、在對 Claude 留一手?
不是。實際的情況是:
Claude 是這個工具的預設供應商,也是我自己開發時用的。
包括這個工具的多語言重構、深色模式、RWD 修正、Prompt 稽核,全部是 Claude 做的。這件事我在前面十五天已經寫得很清楚了。
Adapter Pattern 不是為了離開誰,是為了讓工具的壽命不綁在任何單一外部服務的壽命上。
這兩件事完全不衝突。就像我信任中華電信,但我還是會租第二條線。
工程上的信任,是「我知道你會出問題時我有辦法」,不是「我相信你不會出問題」。
Adapter Pattern 是一個非常基礎的設計模式,任何一本 Design Patterns 的書都在講。
但我發現真正的難處不在「知道這個模式」,在判斷什麼東西該被抽象化。
抽象化是有成本的——多一層間接、多一份心智負擔。抽象錯了地方,就是過度工程。
而判斷該抽象哪裡,靠的不是設計模式的知識,是你對哪些東西會變、哪些不會變的預測。
我押了「供應商會變、契約不會變」。二十年的 IT 經驗告訴我這個押注很安全。
明天預告: 契約定好了,那實作起來呢?我原本以為接完 Claude 再接 Gemini 會很快——畢竟都是「送訊息、拿回覆」。實際上,兩家在八個維度上都不一樣。
作者:Rich Chang | IT 基礎建設工程師 | 越南・柬埔寨・台灣